let Mongodb = require('../../database/mongodb');
let exceljs = require('../../utils/exceljs');
let utils = require("../../utils/utils");

class CommonExportService {
  constructor () {
    this.dataCache = []
  }

  /**
   * 通用导出.
   * params {
   *   tableName: "",
   *   init: {
   *     enumTypes: [],
   *     tableConfigs: []
   *   },
   *   header: [
   *     { title: '序号', width: 10, type: 'index|enum|table|default|custom' }
   *   ],
   *   condition: {}
   * }
   */
  getExcel (params) {
    let workbook = exceljs.createWorkBook()
    let worksheet = workbook.getWorksheet(1)
    worksheet.columns = params.header
    exceljs.setHeaderRowStyle(worksheet)
    return new Promise((resolve, reject) => {
      initFormateData.call(this, params).then(() => {
        return getData(params.tableName, params.params)
      }).then((data) => {
        return this.formateData(data, params)
      }).then((data) => {
        worksheet.addRows(data)
        exceljs.setDataRowStyle(worksheet, data)
        resolve(workbook)
      }).catch((err) => {
        reject(err)
      })
    })
  }

  // 格式化数据
  getPropertyValue (key, id, idName = 'id', valueName = 'name') {
    if (id && this.dataCache[key] && this.dataCache[key].length > 0) {
      let data
      for (let index = 0; index < this.dataCache[key].length; index++) {
        const item = this.dataCache[key][index];
        if (item[idName] == id) {
          data = item
        }
      }
      if (data && data[valueName]) {
        if (data['version']) {
          return data[valueName] + '(' + data['version'] + ')'
        } else {
          return data[valueName]
        }
      } else {
        return ''
      }
    } else {
      return ''
    }
  }
  
  // 格式化数据
  dataFormater (key, id, idName = 'id', valueName = 'name') {
    if (id && this.dataCache[key] && this.dataCache[key].length > 0) {
      let data
      for (let index = 0; index < this.dataCache[key].length; index++) {
        const item = this.dataCache[key][index];
        if (item[idName] == id) {
          data = item
        }
      }
      if (data && data[valueName]) {
        if (data['version']) {
          return data[valueName] + '(' + data['version'] + ')'
        } else {
          return data[valueName]
        }
      } else {
        return ''
      }
    } else {
      return ''
    }
  }

  // 格式化列表数据
  dataArrFormater (key, idArr, idName = 'id', valueName = 'name') {
    if (idArr && this.dataCache[key] && this.dataCache[key].length > 0) {
      let datas = []
      for (let index = 0; index < this.dataCache[key].length; index++) {
        const item = this.dataCache[key][index];
        if (idArr.indexOf(item[idName]) != -1) {
          datas.push(item)
        }
      }
      var names = ''
      for (var i = 0; i < datas.length; i++) {
        if (i !== datas.length - 1) {
          names += (datas[i][valueName] + ',')
        } else {
          names += datas[i][valueName]
        }
      }
      return names
    } else {
      return ''
    }
  }

  /**
   * 格式化金额显示
   * @param {*金额} s
   * @param {*保留位数} n
   */
  numberFormater (s, n) {
    if (s === undefined) return ''
    n = n > 0 && n <= 20 ? n : 2
    s = parseFloat((s + '').replace(/[^\d\\.-]/g, '')).toFixed(n) + ''
    let l = s.split('.')[0].split('').reverse()
    let r = s.split('.')[1]
    let t = ''
    for (let i = 0; i < l.length; i++) {
      t += l[i] + ((i + 1) % 3 === 0 && (i + 1) !== l.length ? ',' : '')
    }
    return t.split('').reverse().join('') + '.' + r
  }

  /**
   * boolean值转换
   * @param {*} b 
   */
  booleanFormatter (b, c = '是'){
    if (b) {
      return c
    }
  }


  // 格式化日期
  dateFormater (dateNum, fmt) {
    if (!dateNum) {
      return ''
    }
    var date = new Date(dateNum)
    var o = {
      'M+': date.getMonth() + 1,
      'd+': date.getDate(),
      'h+': date.getHours(),
      'm+': date.getMinutes(),
      's+': date.getSeconds(),
      'q+': Math.floor((date.getMonth() + 3) / 3),
      'S': date.getMilliseconds()
    }
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
    }
    for (var k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
      }
    }
    return fmt
  }

  // 子类覆盖该方法
  formateData (dataList, params) {
    return new Promise(async (resolve, reject) => {
      let rowDatas = []
      let data = {}
      for (let i = 0, len = dataList.length; i < len; i++) {
        data = dataList[i]
        console.log(data)
        let row = await this.formateRowData(data, params, i)
        rowDatas.push(row)
      }
      resolve(rowDatas)
    })
  }

  formateRowData (data, params, i) {
    return new Promise(async (resolve, reject) => {
      let row = [];
      let ext = {};
      for (let index = 0; index < params.header.length; index++) {
        const col = params.header[index];
        ext = col.ext;
        if (ext.type === "index") {
          row.push(i + 1);
        } else if (ext.type === "enum") {
          if (ext.mutil) {
            row.push(this.dataArrFormater(ext.key, data[ext.prop], ext.value || "value", ext.label || "name"));
          } else {
            row.push(this.dataFormater(ext.key, data[ext.prop], ext.value || "value", ext.label || "name"));
          }
        } else if (ext.type === "table") {
          if (ext.mutil) {
            row.push(this.dataArrFormater(ext.key, data[ext.prop], ext.value || "_id", ext.label || "name"));
          } else {
            row.push(this.dataFormater(ext.key, data[ext.prop], ext.value || "_id", ext.label || "name"));
          }
        } else if (ext.type === "date") {
          row.push(this.dateFormater(data[ext.prop], 'yyyy-MM-dd'));
        } else if (ext.type === "date_month") {
          row.push(this.dateFormater(data[ext.prop], 'yyyy-MM'));
        } else if (ext.type === "date_year") {
          row.push(this.dateFormater(data[ext.prop], 'yyyy'));
        } else if (ext.type === "date_time") {
          row.push(this.dateFormater(data[ext.prop], 'yyyy-MM-dd hh:mm'));
        } else if (ext.type === "custom") {
          let result = await this[ext.func](data);
          row.push(result);
        } else {
          if (data[ext.prop]) {
            row.push(data[ext.prop])
          } else {
            row.push("")
          }
        }
      }
      resolve(row)
    })
  }
   
  // 自定义函数
  // 特殊处理用户角色导出，一个用户有多个角色
  roleProcess(data) {
    let result = "";
    return new Promise((resolve, reject) => {
      if (data._id) {
        if (this.dataCache["userRoles"].length > 0 &&  this.dataCache["roles"].length > 0 ) {
          let roleIds = [];
          this.dataCache["userRoles"].forEach(userRole => {
            if (userRole.userId === String(data._id)) {
              roleIds.push(userRole.roleId);
            }
          })
          if (roleIds.length > 0) {
            this.dataCache["roles"].forEach(role => {
              if (roleIds.includes(String(role._id))) {
                result += role.name + "、";
              }
            })
          }
        }
      }
      resolve(result.slice(0, -1));
    });
  }

  // 突击内容
  rushjobContent(data) {
    return new Promise((resolve, reject) => {
      let startTime = this.dateFormater(data.startTime, 'yyyy-MM-dd');
      resolve(`${startTime} ${data.workNote}`);
    });
  }

  // 任务导出提醒
  taskRemind(data) {
    return new Promise((resolve, reject) => {
      let count = utils.dateDiffInWeekdays(new Date(), new Date(data.end_date));
      if (count > 0) {
        resolve(`剩余${count}天`);
      } else if (count < 0) {
        resolve(`超期${Math.abs(count)}天`);
      } else {
        resolve("今天到期")
      }
    });
  }

  // 评论导出
  comments(data) {
    return new Promise((resolve, reject) => {
      Mongodb.find("comment", { businessId: data._id }, {}, {}, (err, docs) => {
        if (err) {
          reject(err);
        } else {
          let result = "";
          if (docs && docs.length > 0) {
           docs.forEach(item => {
            if (result) {
              result += "\n\t";
            }
            let optUser = this.dataFormater("users", item.optUser, "_id", "userName");
            let optDate = this.dateFormater(item.optDate, 'yyyy-MM-dd');
            let optInfo = item.optInfo;
            result += `${optDate} ${optUser} ${optInfo}`
           })
          }
          resolve(result);
        }
      });
    });
  }
}

function processCondtion (condition) {
  let result = {}
  for (let name in condition) {
    if (name === 'like') {
      for (let c in condition[name]) {
        if (condition.like[c]) {
          result[c] = new RegExp(condition.like[c], 'i')
        }
      }
    } else if (Array.isArray(condition[name])) {
      result[name] = []
      for (let index = 0; index < condition[name].length; index++) {
        const element = condition[name][index]
        result[name].push(processCondtion(element))
      }
    } else {
      result[name] = condition[name]
    }
  }
  return result
}

// 私有方法
function getData (tableName, queryParam) {
  return new Promise((resolve, reject) => {
    let conditions = processCondtion(queryParam.condition)
    if (!queryParam.options) {
      queryParam.options = {}
    }
    console.log(tableName)
    console.log(conditions)
    Mongodb.find(tableName, conditions, queryParam.options.fields || null, queryParam.options.sort, (err, docs) => {
      if (err) {
        reject(err);
      } else {
        resolve(docs);
      }
    });
  });
}

function getTableData (config) {
  return new Promise((resolve, reject) => {
    Mongodb.find(config.tableName, config.condition || {}, config.fields ||{}, {}, (err, docs) => {
      if (err) {
        reject(err);
      } else {
        this.dataCache[config.tableName] = docs
        resolve();
      }
    });
  });
}

function getEnum (enumTypeKey) {
  return new Promise((resolve, reject) => {
    Mongodb.find('param_exts', {csName: enumTypeKey}, {}, {}, (err, docs) => {
      if (err) {
        reject(err);
      } else {
        this.dataCache[enumTypeKey] = docs
        resolve();
      }
    });
  });
}

function initFormateData (params) {
  return new Promise((resolve, reject) => {
    const enumPromise = params.enumTypes.map((key) => {
      return getEnum.call(this, key);
    });
    const baseInfoPromise = params.tableConfigs.map((config) => {
      return getTableData.call(this, config)
    })
    Promise.all(enumPromise.concat(baseInfoPromise)).then((data) => {
      resolve()
    }).catch((err) => {
      reject(err)
    })
  })
}

module.exports = new CommonExportService()